/*-------------------------------------------------------------------------------------------------*/
/*                                                                                                 */
/* Copyright (c) 2008 Nuvoton Technology Corporation                                               */
/* All rights reserved                                                                             */
/*                                                                                                 */
/*-------------------------------------------------------------------------------------------------*/
/* File Name:                                                                                      */
/*     smartcard.c                                                                                 */
/* Description:                                                                                    */
/*     This file contains smartcard driver supported for Nuvoton NUC900 MCU                        */
/* History:                                                                                        */
/*                                                                                                 */
/* Project:                                                                                        */
/*-------------------------------------------------------------------------------------------------*/


#ifdef ECOS
#   include "stdlib.h"
#   include "string.h"
#   include "drv_api.h"
#   include "diag.h"
#   include "wbtypes.h"
#   include "wbio.h"
#   define IRQ_SC_CARD0    0x01000000
#   define IRQ_SC_CARD1    0x02000000
#   define IRQ_SC_GROUP    25
#else
#   include <stdio.h>
#   include <stdlib.h>
#   include <string.h>
#   include "wblib.h"
#endif

#include "NUC900_smartcard.h"
#include "NUC900_reg.h"
#include "wberrcode.h"

//#define SC_DEBUG
//#define SC_DEBUG_PRINT_LINE
//#define SC_DEBUG_ENABLE_ENTER_LEAVE
//#define SC_DEBUG_ENABLE_MSG
//#define SC_DEBUG_ENABLE_MSG2



#ifdef SC_DEBUG
#   ifdef ECOS
#       define PDEBUG					diag_printf
#   else
#       define PDEBUG					sysprintf
#   endif
#else
#   define PDEBUG(...)
#endif

#ifdef SC_DEBUG_PRINT_LINE
#   ifdef ECOS
#       define PRN_LINE()				diag_printf("[%-20s] : %d\n", __func__, __LINE__)
#   else
#       define PRN_LINE()				sysprintf("[%-20s] : %d\n", __func__, __LINE__)
#   endif
#else
#   define PRN_LINE()
#endif

#ifdef SC_DEBUG_ENABLE_ENTER_LEAVE
#   ifdef ECOS
#       define ENTER()					diag_printf("[%-20s] : Enter...\n", __func__)
#       define LEAVE()					diag_printf("[%-20s] : Leave...\n", __func__)
#   else
#       define ENTER()					sysprintf("[%-20s] : Enter...\n", __func__)
#       define LEAVE()					sysprintf("[%-20s] : Leave...\n", __func__)
#   endif
#else
#   define ENTER()
#   define LEAVE()
#endif

#ifdef SC_DEBUG_ENABLE_MSG
#   ifdef ECOS
#       define MSG(_mvar_msg)				diag_printf("[%-20s] : %s\n", __func__, _mvar_msg)
#   else
#       define MSG(_mvar_msg)				sysprintf("[%-20s] : %s\n", __func__, _mvar_msg)
#   endif
#else
#   define MSG(_mvar_msg)
#endif

#ifdef SC_DEBUG_ENABLE_MSG2
#   define MSG2(_mvar_fmt, _mvar_arg...)			PDEBUG("[%-20s] : "_mvar_fmt, __func__, ##_mvar_arg)
#   define PRNBUF(_mvar_buf, _mvar_count)		{int i;MSG2("CID Data: ");for(i=0;i<_mvar_count;i++)\									PDEBUG("%02x ", buf[i]);PDEBUG("\n");}
#else
#   define MSG2(...)
#   define PRNBUF(_mvar_buf, _mvar_count)
#endif

#define __EVB__    /* evaluation board */


#if defined (__EVB__)
#   define FREQ_MULTIPLE			1
#else
#   define FREQ_MULTIPLE			1  /* This value is board dependent */
#endif

#define SC_OUT( _mvar_dev, _mvar_byte, _mvar_addr)		outpw((_mvar_dev)->base + _mvar_addr, _mvar_byte)
#define SC_IN(_mvar_dev, _mvar_addr)		inpw((_mvar_dev)->base + _mvar_addr)



#define SC_IS_PRESENT(_mvar_dev)		(SC_IN(_mvar_dev, SC_ISR) & 0x20)
#define SC_DEACTIVATE_CARD(_mvar_dev)	SC_OUT(_mvar_dev, 0, SC_TMR)  /* Pull RST pin low */
#define SC_POWER_DOWN(_mvar_dev)		SC_OUT(_mvar_dev, SC_IN(dev, SC_IER) | 0x80, SC_IER)
#define SC_POWER_ON(_mvar_dev)			SC_OUT(_mvar_dev, SC_IN(dev, SC_IER) & 0x77f, SC_IER)
#define SC_DATA_READY(_mvar_dev)		(SC_IN(_mvar_dev, SC_SCSR) & 0x01)
#define SC_IS_DATA_SEND(_mvar_dev)		(SC_IN(_mvar_dev, SC_SCSR) & 0x20)
#define SC_GET_ONE_BYTE(_mvar_dev)		(UINT8)(SC_IN(_mvar_dev, SC_RBR) & 0xff)
#define SC_PUT_ONE_BYTE(_mvar_dev, _mvar_data)		SC_OUT(_mvar_dev, _mvar_data, SC_TBR)
#define SC_CLEAR_FIFO(_mvar_dev)		do{SC_OUT(_mvar_dev, 0x06 | 0x38, SC_SCFR);}while(0)   /* Rest both Tx/Rx FIFO */
#define SC_INDORECT_CONVENTION(_mvar_dev)	SC_OUT(_mvar_dev, SC_IN(_mvar_dev, SC_SCCR) | 0x40, SC_SCCR)



struct sc_parameter{
    UINT32 n, t;		/* amount of etu in cycles, and others are in etus */
    UINT32 cwt, bwt, wwt;
    UINT32 fi, di;		/* default value is 372 , 1 */
};

typedef struct{
    INT32 base /*, num*/;
    volatile UINT32 op_state;		/* 0 - everything goes well, 1 - some error occured */
    volatile INT32 errno;
    UINT32 openflag;
    UINT32 clock;	/* frequence in KHz */
    UINT32 etu; 		/* in millisecond */
    UINT32 voltage;
    UINT32 conv;

    struct sc_parameter para;

    UINT8 atr[33];
    UINT32 atr_len;

    UINT8 *snd_buf, *rcv_buf;
    volatile INT32 snd_pos, snd_len, rcv_len, rcv_pos;
    volatile INT32 rcv_cnt;  /* cnt is current received data number in write stage read index in read stage */
    volatile UINT32 bCardRemoved;

}sc_dev;

#ifdef ECOS
cyg_interrupt _ScInterrupt_L;
cyg_handle_t  _ScInterruptHandle_L;
#endif

/* global variable for SmartCard Device */
__align(4 * 1024) static sc_dev _ScDevice_L[SMARTCARD_NUM];


/* 7816-3 1997 Table 7, 8 */
static INT32 _Ftab_L[] = { 372, 372, 558,  744, 1116, 1488, 1860, -1,
                           -1, 512, 768, 1024, 1536, 2048,   -1, -1
                         };
static INT32 _Dtab_L[] = { -1, 1, 2, 4, 8, 16, 32, -1, 12, 20, -1, -1, -1, -1, -1, -1 };

/* Declare in advance */
static INT _ScDoPPS(sc_dev *dev, INT32 f, INT32 d, INT32 t);
static INT _ScWarmReset(sc_dev *dev);

// This is a board dependent function.
static VOID _ScConfigPower(sc_dev *dev)
{
    /* On module test board, power is configured manually */
    /* Evaluation board apply 3V only */
#if defined (__EVB__)
    return;
#else
    /* select power supply */
    switch (dev->voltage){
    case SC_ISO_OPERATIONCLASS_A:		/* 5v */
        /* TODO: configure VCC to 5V according to hardware design */
        break;

    default:
    case SC_ISO_OPERATIONCLASS_B:		/* 3v */
        /* TODO: configure VCC to 3V according to hardware design */
        break;
    }

    return;
#endif
}


static INT _ScMatchReader(INT32 fi, INT32 di)
{
    INT32 i;

    ENTER();

    i = fi/di;

    if ( (i % 31) == 0)
        return 0;
    else if ( (i % 32) == 0)
        return 0;
    else
        return -1;

}

static VOID _ScSetBaudrate(sc_dev *dev, INT32 fi, INT32 di)
{
    UINT8 d;
    INT32 t, psc, pdr;

    t = fi / di;

    if ((t % 31) == 0){
        psc = 31;
        pdr = t / 31;
    }
    else{
        psc = 32;
        pdr = t / 32;
    }

    psc *= FREQ_MULTIPLE;

    SC_OUT(dev, pdr, SC_CBR);

    /* set BDLAB = 1 */
    d = SC_IN(dev, SC_SCCR);
    d |= 0x80;
    SC_OUT(dev, d, SC_SCCR);

    /* set Baud rate divisor */
    SC_OUT(dev, psc & 0xff, SC_BLL);
    SC_OUT(dev, (psc >> 8) & 0xff, SC_BLH);

    /* set BDLAB = 0 */
    d &= 0x7f;
    SC_OUT(dev, d, SC_SCCR);

}


static void _ScSetReaderParameter(sc_dev *dev)
{
    /* set reader baud rate and update dev->clock , so we can calcute etu */
    ENTER();

    _ScSetBaudrate(dev, dev->para.fi, dev->para.di);

    dev->etu = (dev->para.fi * 1000 / dev->para.di) / dev->clock;

    /* 6.5.3                                                          */
    /* To avoid re-transmit problem on T = 0, GTR sould at least be 3 */
    if (dev->para.n == 255 && dev->para.t == 1)
        SC_OUT(dev, 1, SC_GTR);
    else if (dev->para.n == 255 && dev->para.t == 0)
        SC_OUT(dev, 3, SC_GTR);
    else
        SC_OUT(dev, (dev->para.n == 0) ? 3 : (2 + dev->para.n), SC_GTR);

    LEAVE();

}


static VOID _ScResetReader(sc_dev *dev)	//modified by qfu
{
    UINT32 d;

    ENTER();

    /* set BDLAB = 0 */
    d = SC_IN(dev, SC_SCCR);
    d &= 0x7f;
    SC_OUT(dev, d, SC_SCCR);
#if defined (__EVB__)
    SC_OUT(dev, 0x40, SC_ECR);	/* set SCCLK to 2.5Mhz, this is board dependent TODO: read APB clk */
#else
    SC_OUT(dev, 0x50, SC_ECR);	/* set SCCLK to 2.5Mhz, this is board dependent */
#endif
    SC_OUT(dev, 0x06 | 0x38, SC_SCFR);	/* Set FIFO threshold to 1, reset FIFO, disable re-transmit on error */


    d = SC_IN(dev, SC_IER);

    d = 0x788;				/* enabel card insert/removed interrupt */

    SC_OUT(dev, d, SC_IER);


    /* init sc_dev structure */
    dev->clock = (5 / FREQ_MULTIPLE) * 1000;

    dev->etu = 149 ;  /* the original value 104 is for 3.58 crystal, 149 is for 2.5M input */
    dev->para.cwt = 9600;
    dev->para.bwt = 9600;
    dev->para.wwt = 9600; /* unit is etu */


    LEAVE();

}



static VOID _ScActivateCard(sc_dev *dev)
{
    UINT32 d;
    /* remain is the remaining ATR length expecting, this value would be update at run time, offset stores distance to the next TD */
    INT32 remain = 2 /* TS & T0 */, offset = -1, tck = 0;
    ENTER();


    _ScResetReader(dev);
    SC_OUT(dev, 0x10, SC_SCCR);  	// Even parity enable


    SC_POWER_ON(dev);
    d = SC_IN(dev, SC_IER);


    SC_OUT(dev, 0x00, SC_TOC);

    /* wait for 40000 clks before pull high RST	*/
    SC_OUT(dev, 40000/372*FREQ_MULTIPLE, SC_TOIR1);  /* This is board dependent code. 40000/372*2 = 215 */
    SC_OUT(dev, 0x10, SC_TOC);
    while (dev->errno != SC_ERR_TIMEOUT && dev->errno != SC_ERR_CARD_REMOVED); /* if card pulled out, timeout interrupt will never happen */
    if (!SC_IS_PRESENT(dev))
        return;

    dev->errno = 0;



    d = SC_IN(dev, SC_TMR);		/* Pull RST high */
    d |= 0x02;
    SC_OUT(dev, d, SC_TMR);

    d = SC_IN(dev, SC_SCCR);		/* set BDLAB = 1 */
    d |= 0x80;
    SC_OUT(dev, d, SC_SCCR);

    SC_OUT(dev, (31 * FREQ_MULTIPLE) & 0xff, SC_BLL);
    SC_OUT(dev,  ((31 * FREQ_MULTIPLE) >> 8)& 0xff, SC_BLH);

    d = SC_IN(dev, SC_SCCR);		/* set BDLAB = 0 */
    d &= 0x7f;
    d |= 8;  // Set to T= 1. Use parse ATR to check error message.
    SC_OUT(dev, d, SC_SCCR);

    SC_OUT(dev, 2, SC_GTR);		/* guard time = 12 etu*/


    /* read ATR */
    dev->atr_len = 0;
#ifdef ECOS
	cyg_scheduler_lock();
#endif

    SC_OUT(dev, 0x00, SC_TOC);
    SC_OUT(dev, 40000/372 * FREQ_MULTIPLE, SC_TOIR1);  /* This is board dependent code. 40000/372*2 = 215 */
    SC_OUT(dev, 9600 * FREQ_MULTIPLE, SC_TOIR2);
    SC_OUT(dev, 0x210, SC_TOC);

    /* No worry receive error here, it will be caught while parsing ATR  */
    while ((dev->errno !=  SC_ERR_TIMEOUT) && (dev->errno != SC_ERR_CARD_REMOVED) && remain) {
        if ((d = SC_IN(dev, SC_SCSR)) & 0x700) {
            break;  /* Time out 'cos we read SCSR to see if data ready, sometimes we'll miss timeout interrupt! */
        } else if (d & 0x01)	{
            SC_OUT(dev, 0x200, SC_TOC);  // Stop timer 1.
            dev->atr[dev->atr_len] = SC_GET_ONE_BYTE(dev);
            remain--;
            offset--;
            if (dev->atr_len == 0) {
                if (dev->atr[dev->atr_len] == 0x03) {
                    SC_INDORECT_CONVENTION(dev);
                    dev->atr[dev->atr_len] = 0x3f;
                }
            }else if (dev->atr_len == 1) {
                remain += (dev->atr[dev->atr_len] & 0xf); /* Historical byte */
                offset = 0; /* T0 contains Y(x) as well */
            }
            if ((offset == 0)) {

                if (dev->atr[dev->atr_len] & 0x10)
                {
                    ++remain;
                    ++offset;
                }
                if (dev->atr[dev->atr_len] & 0x20)
                {
                    ++remain;
                    ++offset;
                }
                if (dev->atr[dev->atr_len] & 0x40)
                {
                    ++remain;
                    ++offset;
                }
                if (dev->atr[dev->atr_len] & 0x80)
                {
                    ++remain;
                    ++offset;
                    if ((tck == 0) && (dev->atr_len != 1) && ((dev->atr[dev->atr_len] & 0xf) != 0)) {
                        ++remain; /*tck exist */
                        tck = 1;
                    }
                }else
                    offset = -1;
            }

            dev->atr_len++;
            if (dev->atr_len >= 33)
                break;
        }
    }

    SC_OUT(dev, 0x00, SC_TOC);
#ifdef ECOS
	cyg_scheduler_unlock();
#endif    
#if 0
    if (remain ==0)
        sysprintf("remain == 0\n");
    else
        sysprintf("ooops\n");
#endif

    d = SC_IN(dev, SC_SCCR);
    d &= ~8;  // Switch back to T = 0
    SC_OUT(dev, d, SC_SCCR);	


#if 0
    {
        INT32 j;
        PDEBUG("ATR : Length : %d\n", dev->atr_len);
        for ( j = 0; j < dev->atr_len; j ++){
            PDEBUG("%02x ", dev->atr[j]);
        }
        PDEBUG("\n");
    }
#endif
    /* Shouldn't worried about card removal at the moment, app will find out during read/write */


    LEAVE();
}

static INT _ScCheckATR(sc_dev *dev)
{
    INT32 i = 2, tck, h;
    UINT8 *atr = dev->atr, c;

    ENTER();


    /* invalid length of atr */
    if (dev->atr_len < 2)
        return SC_ERR_UNSUPPORTEDCARD;

    dev->conv = 0;

    if ( *atr == 0x03){ /* TS */
        dev->conv = 1;

    }

    if ( *atr != 0x3b && *atr != 0x3f )
        return SC_ERR_UNSUPPORTEDCARD;		/* unknow convention */
    atr++;

    c = *atr++;
    tck = 0;
    h = c & 0x0f;  /*  historical byte length */

    while (1){
        if (c & 0x10)
        {
            atr++;
            i++;
        }
        if (c & 0x20)
        {
            atr++;
            i++;
        }
        if (c & 0x40)
        {
            atr++;
            i++;
        }
        if (c & 0x80){
            c = *atr;
            atr++;
            i++;
            tck = (c & 0x0f) != 0;
        }else
            break;

        if ( (atr+h) > (dev->atr + dev->atr_len)){
            PDEBUG("1lib : length check failed\n");
            return SC_ERR_UNSUPPORTEDCARD;
        }
    }

    if (tck != 0) i++;


    if ( (i+h) != dev->atr_len){
        PDEBUG("lib : length check failed\n");
        return SC_ERR_UNSUPPORTEDCARD;
    }

    if (tck != 0){
        c = dev->atr[0];
        for (i = 1; i < dev->atr_len; i++)
            c ^= dev->atr[i];
        if (c != 0)
            return SC_ERR_UNSUPPORTEDCARD;
    }

    LEAVE();

    return 0;
}

/* ATRIB = A(nswer) T(o) R(eset) I(nterface) B(yte) */
#define SC_ATRIB_TAI	0
#define SC_ATRIB_TBI	1
#define SC_ATRIB_TCI	2
#define SC_ATRIB_TDI	3

static INT _ScParseATR(sc_dev * dev)
{
    INT32 i, retval;
    UINT8 td;
    PUINT8 atr = dev->atr;
    UINT8 n, t, f, d;
    struct {
        UINT8 data;
        UINT8 present;
    }ibyte[4][4];

    ENTER();

    memset(&ibyte, 0, sizeof(ibyte));

    atr ++;
    td = *atr++;
    i = 0;

    while (i<8){

        /* TAi present */
        if ( td & 0x10){
            ibyte[i][SC_ATRIB_TAI].data = *atr++;
            ibyte[i][SC_ATRIB_TAI].present =1 ;
        }

        /* TBi present */
        if ( td & 0x20){
            ibyte[i][SC_ATRIB_TBI].data = *atr++;
            ibyte[i][SC_ATRIB_TBI].present =1 ;
        }

        /* TCi present */
        if ( td & 0x40){
            ibyte[i][SC_ATRIB_TCI].data = *atr++;
            ibyte[i][SC_ATRIB_TCI].present =1 ;
        }

        /* TDi present */
        if ( td & 0x80){
            ibyte[i][SC_ATRIB_TDI].data = *atr++;
            ibyte[i][SC_ATRIB_TDI].present =1 ;
            td = ibyte[i][SC_ATRIB_TDI].data;
            i++;
        }
        else
            break;

    }

    f = d = 1;

    /* set f and d */
    if (ibyte[0][SC_ATRIB_TAI].present){
        f = (ibyte[0][SC_ATRIB_TAI].data >> 4) & 0x0f;
        d = ibyte[0][SC_ATRIB_TAI].data  & 0x0f;
    }

    n = 0;

    if (ibyte[0][SC_ATRIB_TCI].present)
        n = ibyte[0][SC_ATRIB_TCI].data;

    t = 0;

    if (ibyte[1][SC_ATRIB_TAI].present){	/* in specific mode */
        t = ibyte[1][SC_ATRIB_TAI].data & 0x0f;

        if (ibyte[1][SC_ATRIB_TAI].data & 0x10){
            f = 0;
            d= 1;		/* default value */
        }

        if (_ScMatchReader(_Ftab_L[f], _Dtab_L[d]) == 0){	/* reader supported mode? */
            /* do nothing, */
            ;
        }
        else{
            if (!(ibyte[1][SC_ATRIB_TAI].data & 0x80)){	/* capable to change mode */
                retval = _ScWarmReset(dev);	/* change to negotiable mode */
                if (retval != 0)
                    return retval;
                f = 0;
                d = 1;
                t = 0;
                retval = _ScDoPPS(dev, f, d, t);	/* parameter and protocol select */
                if (retval != 0)
                    return retval;
            }
            else
                return SC_ERR_UNSUPPORTEDCARD;
        }

    }
    else{
        /* whatever reader support or not , keep in default mode */

        f = 0;
        d = 1; // t = 0;

    }

    dev->para.fi = _Ftab_L[f];
    dev->para.di = _Dtab_L[d];
    dev->para.t = t;
    dev->para.n = n;

    /* calculate cwt, bwt, etu, etc... */
    if ( t == 1){
        /* t = 1, not implemented yet */
        MSG("Not supported T=1 protocol\n");
        return SC_ERR_UNSUPPORTEDCARD;

    } else if (t == 0){	/* t = 0 , or others */
        int wi = 10;

        if (ibyte[1][SC_ATRIB_TCI].present)
            wi = ibyte[1][SC_ATRIB_TCI].data;

        dev->para.wwt = dev->para.bwt = dev->para.cwt = 960 * wi * dev->para.di; //8.2, but use etu as unit
    }else
        return SC_ERR_UNSUPPORTEDCARD;

    if (_ScDoPPS(dev, f, d, t) != 0)
        return SC_ERR_READ;

    _ScSetReaderParameter(dev);

    LEAVE();

    return 0;
}

static INT _ScColdReset(sc_dev *dev)
{

    ENTER();

    SC_DEACTIVATE_CARD(dev);
    SC_POWER_DOWN(dev);

#if 0
    {
        int i = 0xf000;
        for (; i > 0; i--);

    }
#endif

    _ScConfigPower(dev);

    _ScActivateCard(dev);

    dev->errno = _ScCheckATR(dev);

    if (dev->errno != 0)
        return (dev->errno);

    dev->errno = _ScParseATR(dev);

    LEAVE();

    return (dev->errno);

}

static INT _ScWarmReset(sc_dev *dev)
{

    ENTER();

    SC_DEACTIVATE_CARD(dev);

#if 0
    {
        int i = 0xf000;
        for (; i > 0; i--);
    }
#endif

    _ScActivateCard(dev);

    dev->errno  =_ScCheckATR(dev);

    LEAVE();

    return(dev->errno);

}

/* low level write function                                                                              */
/* Since upper layer function (e.g. scT0Write) clear FIFO before calling this function,                  */
/* This function will put at most 16 bytes and let ISR do the reset transmit job if any data remains     */
static INT32 _ScRawWrite(sc_dev *dev, PUINT8 buf, UINT32 len)
{
    INT32 i, j;

    ENTER();


    if (dev->bCardRemoved) {
        return -SC_ERR_CARD_REMOVED;
    }
    dev->errno = 0;


    dev->snd_buf = buf; /* keep snd_buf in user application, save some memcpy calls */
    dev->snd_len = len;
    dev->snd_pos = 0;
    //dev->op_state = SC_OP_WRITE;

    /* FIFO already cleared in upper level */

    j = (dev->snd_len > 16) ? 16 : dev->snd_len;

	/* Make sure there is sufficient guard time  */

		SC_OUT(dev, SC_IN(dev, SC_GTR), SC_TOIR1);
		SC_OUT(dev, 0x010, SC_TOC);
		while(dev->errno != SC_ERR_TIMEOUT)
			if(dev->bCardRemoved)
				return -SC_ERR_CARD_REMOVED;
				
		dev->errno = 0;	
		dev->op_state = SC_OP_WRITE;
		
#if 1  // test polling mode
    for (i = 0 ; i < j ;i ++)
        SC_PUT_ONE_BYTE(dev, dev->snd_buf[dev->snd_pos++]);
    while (dev->op_state == SC_OP_WRITE && !(volatile INT32)(dev->errno));
#else
	
	//sysprintf("\nt");
	for(i = 0; i < dev->snd_len; i++) {
	//	sysprintf("%02x", dev->snd_buf[dev->snd_pos]);
		SC_PUT_ONE_BYTE(dev, dev->snd_buf[dev->snd_pos++]);
		while(!(SC_IN(dev, SC_SCSR) & 0x60));

	}
#endif

    if (dev->errno)
        return (dev->errno);

    LEAVE();

    return(len);

}

/* low level read function                                                                                    */
/* ISR will do the real receive job.                                                                          */
/* NOTE: This function don't reset rcv->pos, upper layer function needs to decide where the index should be.  */
static INT32 _ScRawRead(sc_dev *dev, PUINT8 *buf, UINT32 len)
{


    ENTER();

    if (dev->bCardRemoved) {

        return -SC_ERR_CARD_REMOVED;
    }
    dev->errno = 0;

    if (len == 0)
        return 0;

    if ( len > MAX_BUF_LEN)
        len = MAX_BUF_LEN;

    *buf = &dev->rcv_buf[dev->rcv_pos];
    dev->rcv_len = len;
    dev->rcv_cnt = 0;

    dev->op_state = SC_OP_READ;
#if 1
    while (dev->op_state == SC_OP_READ && !(volatile INT32)(dev->errno));
#else
		
		//	sysprintf("\nr");
            while (1){
            	if(SC_DATA_READY(dev)) {
                	dev->rcv_buf[dev->rcv_pos + dev->rcv_cnt++] = SC_GET_ONE_BYTE(dev);
          //      	sysprintf("%02x ", dev->rcv_buf[dev->rcv_pos + dev->rcv_cnt - 1]);
				}else
					continue;
                /* FIXME: I know this is evil, better place to stop timer? */
                if (dev->para.t == 0) {
                    /* Disable timer 1, it used as an one shot mode timer in T = 0 protocol, and should be
                     disabled after first byte received */
                    SC_OUT(dev, (SC_IN(dev, SC_TOC) & 0x707), SC_TOC);
                }

                if (dev->rcv_cnt>= dev->rcv_len || dev->rcv_pos + dev->rcv_cnt >= MAX_BUF_LEN){
                    dev->op_state = SC_OP_NOP;
                    break;  /* Drop the data we're not expecting */
                }

            }

#endif

    if (dev->errno)
        return(dev->errno);


    LEAVE();

    return dev->rcv_cnt;

}


static INT _ScDoPPS(sc_dev *dev, INT32 f, INT32 d, INT32 t)
{
    UINT8 buf[4], rbuf[4];
    INT32 retval, i;
    INT32 len = 4;

    ENTER();

    /* default envirment , pps not need */
    if ((f == 0 || f == 1) && d == 1)
        return 0;

    buf[0] = 0xff;
    buf[1] = 0x10 |(t & 0x0f);
    buf[2] = ((f<<4)&0xf0) | (d & 0x0f);
    buf[3] = (buf[0] ^ buf[1] ^ buf[2]);

    SC_CLEAR_FIFO(dev);

    PDEBUG("Sending PPS : %02x %02x %02x %02x\n",
           buf[0], buf[1], buf[2], buf[3]);


    SC_OUT(dev, 0x00, SC_TOC);

#if 0
    {
        int ii = 0xf000;
        for (; ii > 0; ii--);
    }
#endif

    for (i = 0 ; i < len ;i ++) /* FIFO cleared, we can write it directly */
        SC_PUT_ONE_BYTE(dev, buf[i]);

    i = 0;

    SC_OUT(dev, 40000/372*FREQ_MULTIPLE, SC_TOD2);  /* This is board dependent code. 40000/372*2 = 215 */
    SC_OUT(dev, 0x100, SC_TOC);  /* timer 1 may be disable after 1st byte received, we don't want this happen, so usr timer 2 */
    while (!(SC_IN(dev, SC_SCSR) & 0x200) && i < 4) {
        if (SC_DATA_READY(dev))
            rbuf[i++] = SC_GET_ONE_BYTE(dev);
    }

    SC_OUT(dev, 0, SC_TOC);

    retval = SC_ERR_UNSUPPORTEDCARD;

    PDEBUG("Received PPS : %02x %02x %02x %02x\n", rbuf[0], rbuf[1], rbuf[2], rbuf[3]);

    if (rbuf[0] != buf[0])
        return retval;

    if ( (rbuf[1]&0x0f) == (buf[1] &0x0f) &&		/* success */
            ((rbuf[1] & 0xf0) == 0x10 ||(rbuf[1] & 0xf0) == 0x00)){
        PDEBUG("PPS Request Success, now baudrate is %d\n", 9600 * _Dtab_L[d]);
        return 0;
    }

    LEAVE();

    return retval;

}



static INT32 _ScT0Write(sc_dev *dev, PUINT8 buf, UINT32 len)
{
    UINT8 INS = buf[1];
    INT32 lc, le, local_count;
    volatile INT32 i;
    INT32 retval = SC_ERR_CMD;
    PUINT8 pbyte;
    UINT32 wwt = (dev->para.wwt * FREQ_MULTIPLE );

    ENTER();

    /* check for incorrect length */

    if (len < 5 || len > MAX_CMD_LEN)
        return retval;

    if (len !=5 && len != ( buf[4] + 5) && len != (buf[4] + 6))
        return retval;

    lc = 0;
    le = 0;			/* pick lc, le from command string */

    if (len == 5){
        if ( buf[4] != 0)
            le = buf[4];
    }
    else{
        if ( len == (buf[4] + 5))
            lc = buf[4];
        else{
            lc = buf[4] + 1;
            le = buf[len -1];
            if (le == 0)			/* if le appears and it is equal to 0, it means
									max length(256) of data is needed */
                le = 256;
        }
    }

    local_count = 5;


    SC_CLEAR_FIFO(dev);

    SC_OUT(dev, 0x000, SC_TOC);


    /* begin writting 5 bytes command header */
    if ((retval = _ScRawWrite(dev, buf, local_count)) < 0){
        PDEBUG("raw write failed %d\n", retval);
        return SC_ERR_WRITE;
    }
#ifdef ECOS
	cyg_scheduler_lock();
#endif
    do{
        /* get procedure byte */
        do{
            SC_OUT(dev, wwt, SC_TOIR1);
            SC_OUT(dev, 0x010, SC_TOC);  /* Timer 1 one shot mode  */
            if ((retval = _ScRawRead(dev, &pbyte, 1)) < 1){ /* There must be error if we get 0 byte */

                PDEBUG("raw read failed %d\n", retval);
                retval = SC_ERR_READ;
                goto t0WriteExit;
            }
            SC_OUT(dev, 0x00, SC_TOC);

        }while (*pbyte == 0x60);

        if (*pbyte == (INS ^ 0x01) || *pbyte == INS){ /* process all remaining data */
            if (lc != 0)
                local_count = lc;
            else
                local_count = le;
        }else if ((INS ^ 0xfe) == *pbyte || (INS ^ 0xff) == *pbyte){ /* one byte at a time */

            local_count = 1;

        }else if ( (*pbyte&0xf0)==0x60 || (*pbyte&0xf0)==0x90){

            /* It's SW1, we wanna save this byte */
            dev->rcv_pos++;
            SC_OUT(dev, wwt, SC_TOIR1);
            SC_OUT(dev, 0x10, SC_TOC);  /* Timer 1 one shot mode */
            if ((retval = _ScRawRead(dev, &pbyte, 1))  < 1) {	/* read SW2 */ /* There must be error if we get 0 byte */
                goto t0WriteExit;
            }

            dev->rcv_pos++;	/* save SW2 */

            LEAVE();
            /* Reset index, read function expect this value reset to 0 */
            dev->rcv_cnt = 0;
            retval = 0;
            goto t0WriteExit;
        }else{
            PDEBUG("Unknown procedure byte %02x\n", *pbyte);
            retval = SC_ERR_READ;
            goto t0WriteExit;
        }

        /* read/write card according lc, le and local_count */
        if (lc != 0){

            /* if write, a delay is a must before write so that card can have time to
            	enter receiving mode. At least 100us */
            for (i = 0; i < 200; i++);

            if ((retval = _ScRawWrite(dev, buf + len - lc, local_count)) < 0 ){
                PDEBUG("Write Error (%d)\n", retval);

                retval = SC_ERR_WRITE;
                goto t0WriteExit;
            }

            lc -= local_count;
        }
        else{
            /* timer 1 prevent card never reply,
               timer 2 takes care the timeout event for following reply */
            SC_OUT(dev, wwt, SC_TOIR2);
            SC_OUT(dev, wwt, SC_TOIR1);
            SC_OUT(dev, 0x210, SC_TOC);  /* Timer1 one-shot mode, timer 2 auto-reload  */
            if ((retval = _ScRawRead(dev, &pbyte, local_count)) < 0){
                PDEBUG("Read Error(%d)\n", retval);
                SC_OUT(dev, 0, SC_TOC);
                retval = SC_ERR_READ;
                goto t0WriteExit;
            }
            le -= local_count;

            dev->rcv_pos += retval;
            SC_OUT(dev, 0, SC_TOC);
        }

        if (lc <0 || le < 0) {
            retval = SC_ERR_READ;
            goto t0WriteExit;
        }    

    }while (1);

t0WriteExit:
#ifdef ECOS
	cyg_scheduler_unlock();
#endif    
    
    return(retval);

}

/* This function won't report any error status, upper layer already filter out them all. */
static INT32 _ScT0Read(sc_dev *dev, PUINT8 buf, UINT32 len)
{

    ENTER();

    if (dev->rcv_pos == 0) /* no data in rcv_buf */
        return(0);



    if (len >= (dev->rcv_pos - dev->rcv_cnt))		/* return max length */
        len = (dev->rcv_pos - dev->rcv_cnt);

    memcpy(buf, &dev->rcv_buf[dev->rcv_cnt], len);


    dev->rcv_cnt += len;

    LEAVE();

    return(len);


}

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      SC_Read()                                                         */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Read smartcard returned data                                     */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*                                                                       */
/* INPUTS                                                                */
/*      fd          Smartcard interface number                           */
/*      buf         Receive buffer pointer                               */
/*      len         Receive buffer length                                */
/*                                                                       */
/* OUTPUTS                                                               */
/*      > 0          Retrun read length on success                       */
/*      SC_EBUSY      Card busy, ether in write or read state            */
/*      SC_EIO        Card removed, not activated or read/write error    */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*                                                                       */
/*                                                                       */
/* REMARK                                                                */
/*      This function will dispatch jobs to different function according */
/*      to card type                                                     */
/*                                                                       */
/*************************************************************************/

INT32 SC_Read(INT32 fd, PUINT8 buf, UINT32 len)
{

    sc_dev *dev;
    dev = &_ScDevice_L[fd];
    if (fd != 1 && fd != 0)
        return SC_ENODEV;
    if (dev->op_state) /* card busy */
        return SC_EBUSY;
    if (dev->errno != 0) /* some error happened in scWrite, previous transaction must be failed */
        return SC_EIO;
    if (dev->openflag == 0)
        return(SC_EIO);


    if (len == 0)
        return 0;

    if ( len > MAX_BUF_LEN)
        len = MAX_BUF_LEN;


    if (dev->para.t == 0){
        return (_ScT0Read(dev, buf, len));
    } else if (dev->para.t == 1) {
        return SC_EIO; /* Does not support T=1 protocol yet. */
    } else
        return SC_EIO;


}

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      SC_Write()                                                        */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Write command to smartcard                                       */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*                                                                       */
/* INPUTS                                                                */
/*      fd          Smartcard interface number                           */
/*      buf         Transmit buffer pointer                              */
/*      len         Transmit buffer length                               */
/*                                                                       */
/* OUTPUTS                                                               */
/*      > 0           Return write length on success                     */
/*      SC_EBUSY      Card busy, ether in write or read state            */
/*      SC_EIO        Card removed, not activated or read/write error    */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*                                                                       */
/*                                                                       */
/* REMARK                                                                */
/*      This function will dispatch jobs to different function according */
/*      to card type                                                     */
/*      Note, scT(0, 1)Write function must clear FIFO before sending     */
/*      data into FIFO                                                   */
/*                                                                       */
/*************************************************************************/

INT32 SC_Write(INT32 fd, PUINT8 buf, UINT32 len)
{
    sc_dev *dev;

    dev =  &_ScDevice_L[fd];
    if (fd != 1 && fd != 0)
        return SC_ENODEV;

    if (dev->op_state)
        return SC_EBUSY;

    if (dev->errno == SC_ERR_CARD_REMOVED)
        return SC_EIO;

    if (dev->openflag == 0)
        return(SC_EIO);



    if (len == 0)
        return 0;

    if (len > MAX_BUF_LEN)
        len = MAX_BUF_LEN;

    /* Call write means we give up data remain in dev->buf */
    dev->snd_pos = 0;
    dev->rcv_pos = 0;


    if (dev->para.t == 0){

        if ((dev->errno = _ScT0Write(dev, buf, len)) !=0){
            MSG2("write error code %d\n", dev->errno);

            return SC_EIO;
        }

    } else if (dev->para.t == 1){
        return SC_EIO;
    } else
        return SC_EIO;


    return len;

}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      SC_Open()                                                         */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      This function activates the smartcard                            */
/* CALLED BY                                                             */
/*                                                                       */
/* INPUTS                                                                */
/*      param       Interface number, ether 0 or 1                       */
/* OUTPUTS                                                               */
/*       0          Successful                                           */
/*      SC_EBUSY      Interface already opened                             */
/*      SC_EIO        Card removed or unsupport card                       */
/*      SC_ENODEV     Interface number out of range                        */
/*      SC_ENOMEM     Out of memory                                        */
/* HISTORY                                                               */
/*                                                                       */
/* REMARK                                                                */
/*                                                                       */
/*************************************************************************/

INT32 SC_Open(PVOID param)
{
    INT retval, i, fd;
    UINT32 c;
    sc_dev *dev;
    ENTER();


    fd = (INT32)(param);

    if (fd != 0 && fd != 1)
        return SC_ENODEV;


    dev = &_ScDevice_L[fd];
    memset(dev, 0, sizeof(sc_dev));

    if ( dev->openflag != 0 )		/* a card slot can open only once */
        return(SC_EBUSY);

    memset(dev, 0, sizeof(sc_dev));
    dev->base = (fd) ? SCHI1_BA : SCHI0_BA;


    c = SC_IN(dev, SC_ISR);

    MSG2("SC_ISR : [%04x]\n", c);

    if (!( c & 0x20)) {

        dev->bCardRemoved = 1;

        return(SC_EIO);
    } else {
        dev->bCardRemoved = 0;

#ifdef ECOS
        *(unsigned int volatile *)(REG_AIC_GEN) |= ((fd == 0) ? IRQ_SC_CARD0 : IRQ_SC_CARD1);
#else
        sysEnableGroupInterrupt((fd == 0) ? IRQ_SC_CARD0 : IRQ_SC_CARD1);
#endif
        /* 3v start */
        dev->voltage = SC_ISO_OPERATIONCLASS_B;

        for ( i = 0; i < 2; i++){
            if ((retval = _ScColdReset(dev)) != 0){
                dev->voltage = SC_ISO_OPERATIONCLASS_A;  /* 3V failed, try 5V */
                continue;
            }
            break;
        }

        if (retval != 0) {
#ifdef ECOS
            *(unsigned int volatile *)(REG_AIC_GEN) &= ~((fd == 0) ? IRQ_SC_CARD0 : IRQ_SC_CARD1);
#else
            sysDisableGroupInterrupt((fd == 0) ? IRQ_SC_CARD0 : IRQ_SC_CARD1);
#endif
            dev->errno = SC_ERR_UNSUPPORTEDCARD;
            return(SC_EIO);
        }
    }


    dev->rcv_buf = (PUINT8)malloc(MAX_BUF_LEN * sizeof(UINT8));
    if ( dev->rcv_buf == NULL){
#ifdef ECOS
        *(unsigned int volatile *)(REG_AIC_GEN) &= ~((fd == 0) ? IRQ_SC_CARD0 : IRQ_SC_CARD1);
#else
        sysDisableGroupInterrupt((fd == 0) ? IRQ_SC_CARD0 : IRQ_SC_CARD1);
#endif
        SC_DEACTIVATE_CARD(&_ScDevice_L[fd]);
        SC_POWER_DOWN(&_ScDevice_L[fd]);
        return(SC_ENOMEM);
    }

    dev->openflag = 1;
    dev->errno = 0;  /* clear error code set during cold reset */
    /* Enable Tx/Rx, SC_SCSR interrupt now */
    
#if 1  // set 0 to test polling mode   
    c = SC_IN(dev, SC_IER);
    c |= 0x7;
    SC_OUT(dev, c, SC_IER);
#endif

    PDEBUG("Open Success\n");

    LEAVE();

    return 0;

}

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      SC_Close()                                                        */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Release SCHI software resource, disable ISR                      */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/* INPUTS                                                                */
/*      fd          Smartcard interface number                           */
/*                                                                       */
/* OUTPUTS                                                               */
/*       0          Successful                                           */
/*      SC_ENODEV     Interface number out of range                        */
/*      SC_EIO        Card not activated                                   */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/* REMARK                                                                */
/*      none                                                             */
/*                                                                       */
/*************************************************************************/

INT32 SC_Close(INT32 fd)
{
    sc_dev *dev;


    ENTER();

    if (fd != 0 && fd != 1)
        return(SC_ENODEV);

    dev = &_ScDevice_L[fd];
    if (dev->openflag == 0)
        return(SC_EIO);

#ifdef ECOS
    *(unsigned int volatile *)(REG_AIC_GEN) &= ~((fd == 0) ? IRQ_SC_CARD0 : IRQ_SC_CARD1);
#else
    sysDisableGroupInterrupt((fd == 0) ? IRQ_SC_CARD0 : IRQ_SC_CARD1);
#endif
    SC_DEACTIVATE_CARD(dev);
    SC_POWER_DOWN(dev);

#if defined(__EVB__)
    SC_OUT(dev, 0xC0, SC_IER);
#else
    SC_OUT(dev, 0x80, SC_IER);   /* disable all interrupt */
#endif

    free(dev->rcv_buf);

    dev->openflag = 0;

    LEAVE();

    return 0;
}

#ifdef ECOS
static cyg_uint32 _ScISR(cyg_vector_t vector, cyg_addrword_t data)
#else
static VOID _ScISR(PVOID param)
#endif
{
    INT32 isr , d = 0;


    sc_dev *dev= &_ScDevice_L[(*(INT32 volatile *)REG_AIC_GASR & IRQ_SC_CARD0)== IRQ_SC_CARD0 ? 0: 1];
    ENTER();

	//sysprintf("i  %08x\n", dev->base);

    isr = SC_IN(dev, SC_ISR);

    MSG2("INT : SC_ISR : [%02x]  SC_SCSR : [%02x]\n", isr, SC_IN(dev, SC_SCSR));

    if (isr & 0x01)		/* no interupt pending */
        goto exitISR;

    if ((isr & 0x10)){		/* tag card removed */
        MSG2("Card Present Int : SC_ISR : [%02x]\n", isr);

        if ( isr & 0x20){
            MSG("Card Inserted\n");
            dev->bCardRemoved = 0;
        }
        else{
            dev->bCardRemoved = 1;
            MSG("Card Removed\n");
            if (1) {
                SC_DEACTIVATE_CARD(dev);
                SC_POWER_DOWN(dev);
                dev->errno = SC_ERR_CARD_REMOVED;
                dev->op_state = SC_OP_NOP;
                dev->openflag = 0;
                goto exitISR;
            }
        }
    }

    switch ( isr & 0x0f ){

    case 0x02:	/* SC_TBR empty */
        if (dev->op_state == SC_OP_WRITE){
            MSG2("SC_TBR Empty, pos, len : %02x, %02x\n",
                 dev->snd_pos, dev->snd_len);

            if (dev->snd_pos >= dev->snd_len){

                dev->op_state = SC_OP_NOP;
            }
            while ((d++ < 16) && (dev->snd_pos < dev->snd_len))
                SC_PUT_ONE_BYTE(dev, dev->snd_buf[dev->snd_pos++]);
        }
        else{
            /* We'll get in here if there's no data in FIFO and Tx interrupt
               enabled the first time, so do nothing here */
            ;
        }

        break;



    case 0x0c:	/* FIFO data time out, what a good methord */
    case 0x04:	/* SC_RBR data ready */
        if (dev->op_state == SC_OP_READ){
            while (SC_DATA_READY(dev)){
                dev->rcv_buf[dev->rcv_pos + dev->rcv_cnt++] = SC_GET_ONE_BYTE(dev);
               // sysprintf("%02x ", dev->rcv_buf[dev->rcv_pos + dev->rcv_cnt - 1]);

                /* FIXME: I know this is evil, better place to stop timer? */
                if (dev->para.t == 0) {
                    /* Disable timer 1, it used as an one shot mode timer in T = 0 protocol, and should be
                     disabled after first byte received */
                    SC_OUT(dev, (SC_IN(dev, SC_TOC) & 0x707), SC_TOC);
                }

                if (dev->rcv_cnt>= dev->rcv_len || dev->rcv_pos + dev->rcv_cnt >= MAX_BUF_LEN){
                    dev->op_state = SC_OP_NOP;
                    break;  /* Drop the data we're not expecting */
                }

            }

        }  else {  /* Disgard these data */
            SC_CLEAR_FIFO(dev);
        }
        break;

    case 0x06:		/* over run, parity, no stop, silent byte */
        d = SC_IN(dev, SC_SCSR);
        if (dev->op_state){


            MSG2("SC_SCSR : %02x\n", d);

            if ((d & 0x1e) == 0)	/* no error */
                break;

            if (d & 0x02){
                MSG("Over Run\n");
                isr = SC_GET_ONE_BYTE(dev); /* isr used here to avoid compile warning */
            }

            if (d & 0x04){
                MSG("Parity Error\n");
                SC_CLEAR_FIFO(dev);
            }

            if (d & 0x08){
                MSG("No stop bit error\n");
            }

            if (d & 0x10){
                MSG("Silent byte detected\n");
            }

            dev->errno = SC_ERR_READ;
        }
        dev->op_state = SC_OP_NOP;

        break;
    case 0x0e:
        d = SC_IN(dev, SC_SCSR);
        if (d & 0x700) {
            dev->errno = SC_ERR_TIMEOUT;
            dev->op_state = SC_OP_NOP;
        }
        break;

    }

    LEAVE();

exitISR:

#ifdef ECOS
    cyg_drv_interrupt_acknowledge(IRQ_SC_GROUP);
    return CYG_ISR_HANDLED;
#else
    return;
#endif
}


/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      SC_Ioctl()                                                        */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/* INPUTS                                                                */
/*      fd          Interface number                                     */
/*      cmd         Command                                              */
/*      arg0, arg1  Arguments for the command                            */
/* OUTPUTS                                                               */
/*       0          Success                                              */
/*      SC_ENODEV     Interface number out of range                        */
/*      SC_EIO        Card not activated or card removed                   */
/*      SC_ENOTTY     Command not support                                  */
/* HISTORY                                                               */
/*                                                                       */
/* REMARK                                                                */
/*                                                                       */
/*************************************************************************/

INT32 SC_Ioctl(INT32 fd, UINT32 cmd, UINT32 arg0, UINT32 arg1)
{
    INT32 err = 0;
    sc_dev *dev;
    dev =  &_ScDevice_L[fd];
    ENTER();

    if (fd != 0 && fd != 1)
        return SC_ENODEV;
    if (dev->openflag == 0)
        return(SC_EIO);
    if (dev->errno == SC_ERR_CARD_REMOVED)
        return SC_EIO;


    switch (cmd){


    case SC_IOC_GETATR:    /* Get ATR and ATR length */
        memcpy((PVOID)arg0, (PVOID)dev->atr, dev->atr_len);
        *(PINT32)arg1 = dev->atr_len;

        break;
    case SC_IOC_GETERRNO:  /* return latest error number */
        *(PINT32)arg0 = dev->errno;
        break;

    case SC_IOC_ISCARDPRESENT:    /* Check whether card present or not  */

        *(PINT32)arg0 = SC_IS_PRESENT(dev) ? 1 : 0;
        break;

    default:
        return SC_ENOTTY;
    }

    LEAVE();

    return err;
}
/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      SC_Init()                                                         */
/*                                                                       */
/* DESCRIPTION                                                           */
/*      Configure GPIO to SCHI mode, install ISR                         */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/* REMARK                                                                */
/*      This function is board dependent, it probably needs some         */
/*      modifications before it can work properly on your target board   */
/*                                                                       */
/*************************************************************************/

INT32  SC_Init(VOID)
{



    *(UINT32 volatile *)(REG_MFSEL) &= 0xffffff0f;
    *(UINT32 volatile *)(REG_MFSEL) |= 0x50;
    *(UINT32 volatile *)(REG_CLKEN) |= 0x30000;

    /* Need to put this structure in non-cachable region, or application cannot get the status from ISR correctly */
    sysSetCachePages((UINT32)&_ScDevice_L[0], 4 * 1024, CACHE_DISABLE);

#ifdef ECOS

    cyg_drv_interrupt_create(IRQ_SC_GROUP, 10, 0, _ScISR, NULL,
                             &_ScInterruptHandle_L, &_ScInterrupt_L);
    cyg_drv_interrupt_attach(_ScInterruptHandle_L);
    cyg_drv_interrupt_unmask(IRQ_SC_GROUP);

#else
    sysInstallISR(IRQ_LEVEL_1, IRQ_SC_GROUP, (PVOID)_ScISR);
    sysEnableInterrupt(IRQ_SC_GROUP);

    sysSetLocalInterrupt(ENABLE_IRQ);
#endif
    MSG("SmartCard driver has been installed successfully!\n");

    return(0);

}

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*      SC_Exit()                                                         */
/*                                                                       */
/* DESCRIPTION                                                           */
/*     Do nothing                                                        */
/*                                                                       */
/* CALLED BY                                                             */
/*                                                                       */
/*                                                                       */
/* INPUTS                                                                */
/*                                                                       */
/* OUTPUTS                                                               */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/* REMARK                                                                */
/*                                                                       */
/*                                                                       */
/*************************************************************************/

INT32 SC_Exit(VOID)
{

    return(0); /* always success */
}

